################################################################################
# The NOTES CLASS
#   A Graphical User Interface
#
#   Allows user to store and view notes.
#
#   Have a single button on the upper left corner.
#       When clicked, the button will expand to a column of buttons with options
#           such as open other files, create new file, close current file, save, and exit
#       Settings: line color, page color, and others...
#
#   A screen (canvas) filled with or without lines.
#       Provides the user maximum amount of space to take notes
#
#   Highlight feature
#   Zoom Feature
#
#   Store created and modified dates and author name in the saved file
#       Saves the files in different file formats (pdf,ebook, etc.)
################################################################################
#http://www.pythonware.com/media/date/pil-handbook.pdf

#TO ALLOW USER TO OPEN A SET OF NOTES,
#PLEASE PROVIDE A LIST OF FILE PATHS AFTER NOTES CLASS IS CREATED.

#EXAMPLE:
#list = ["/home/quynh/NetBeansProjects/trunk/NewPythonProject/src/mainproject/painting2.gif","/home/quynh/NetBeansProjects/trunk/NewPythonProject/src/mainproject/painting3.gif"]

#self.notesWindow = Toplevel(self.root)
#self.notesWindow.geometry("820x600+0+0")
#self.childNote = NotesClass(self.notesWindow, self, self.loadedData["path"])

#self.childNote.displaySetNotes(list)

from Tkinter import *
from PIL import Image, ImageDraw, ImageColor
from tkColorChooser import askcolor
import tkMessageBox
import tkFileDialog
import os

class NotesClass(object):
    def __init__(self, root, obj, path):
        self.path = path
        self.root = root
        self.obj = obj

        self.childframe = Frame(self.root, bg="black", relief=RIDGE)
        self.childframe

        self.root.resizable(0, 0)
        #Default Notes Settings:
        self.white = '#ffffff'
        self.option = "page"

        self.brushSize = IntVar()
        self.brushSize.set(1)
        self.fromNotesMan = 0
        self.optionOpen = {}
        self.optionOpen["filetypes"] = [("gif", '.gif'), ("ppm", '.ppm')]
        self.optionOpen["multiple"] = 1
        self.optionOpen["parent"] = self.root
        self.currentFileName= os.getcwd()+"/"+ "Untitled.gif"
        self.untitledFile = os.getcwd()+"/"+"Untitled.gif"
        self.color = '#000000'
        self.lastColor = "#000000"
        self.erase = 0
        self.penSize = 1
        self.eraSize = 7
        self.BrSize = 1
        self.lastx = 0
        self.lasty = 0
        self.publishN = BooleanVar(0)
        self.pub = "u"
        self.count = 0
        self.list = []

        self.saved = 1
        self.files = []
        self.iconsList = []
        self.labelsList = []
        self.createWidgets()
        self.createMenu()
        self.root.grid()

    def getHelp(self):
        tkMessageBox.showinfo(
                              "Help", "To change current paper, click on the paper icon and select your choice of paper.\n" +
                              "To change current tools, click the supplies icon and select your choice.\n")

    #Closes the brush scale window
    def closeScale(self):

        if (self.erase == 0):
            self.BrSize = self.penSize = self.brushSize.get()
        else:
            self.BrSize = self.eraSize = self.brushSize.get()

        self.scaleWindow.destroy()
    #Present a scale on the window and allow user to select size of brush
    def selectSize(self):
        self.scaleWindow = Toplevel(self.root)
        self.scale = Scale(self.scaleWindow, label="Brush Size",
                           variable=self.brushSize,
                           from_=1, to=5,
                           showvalue='yes',
                           orient='vertical')
        self.scale.pack(anchor=CENTER)

        button = Button(self.scaleWindow, text="Select Size",
                        command=self.closeScale)
        button.pack(anchor=CENTER)


    #Create just an empty page
    def drawNPage(self):
        if (self.saved==0):
            result = tkMessageBox.askyesno("Discard Notes?", "Are you sure you want to discard unsaved notes?")
            if (result):
                self.drawNewPage()
            else:
                self.saveFile()
        else:
            self.drawNewPage()

    #Create just an empty page
    def drawNewPage(self):
        self.menubar.entryconfig(10,state=NORMAL)
        self.papermenu.entryconfig(2, state=NORMAL)
        self.papermenu.entryconfig(3, state=NORMAL)
        self.papermenu.entryconfig(4, state=NORMAL)
        self.papermenu.entryconfig(5, state=NORMAL)
        self.papermenu.entryconfig(6, state=NORMAL)
        self.currentFileName=self.untitledFile
        self.menubar.entryconfig(11, label=self.path + "/" + ".Untitled.gif")
        self.menubar.entryconfig(5, state=NORMAL)
        self.publishN.set(False)

        del self.background
        self.background = Image.new("RGB", (self.width, self.height), self.white)
        self.drawing = ImageDraw.Draw(self.background)
        self.cv.config(bg='white')
        self.option = "page"
        self.cv.delete(ALL)
        self.saved = 0


    def drawBlank(self):
        self.saved = 0
        self.menubar.entryconfig(5, state=NORMAL)
        self.background.save(self.untitledFile)
        self.openImage(self.untitledFile, 1)
        self.option = "page"


    #Create a yellow notepad
    def drawPad(self):
        self.menubar.entryconfig(5, state=NORMAL)
        self.background.save(self.untitledFile)
        self.openImage(self.untitledFile, 1)
        self.drawLines("npad")

    #Create a College Ruled paper
    def drawCollege(self):
        self.menubar.entryconfig(5, state=NORMAL)
        self.background.save(self.untitledFile)
        self.openImage(self.untitledFile, 1)
        self.drawLines("colg")

    #Create a Wide Ruled paper
    def drawWide(self):
        self.menubar.entryconfig(5, state=NORMAL)
        self.background.save(self.untitledFile)
        self.openImage(self.untitledFile, 1)
        self.drawLines("wide")


    #Create Grid lined paper
    def drawGrid(self):
        self.menubar.entryconfig(5, state=NORMAL)
        self.background.save(self.untitledFile)
        self.openImage(self.untitledFile,1)
        self.drawLines("grid")

    #Draw the lines on the screen
    def drawLines(self, option):
        self.saved = 0
        self.option = option
        #Default spacing and lines
        self.start = 130
        self.end = self.height
        #Vertical lines spacing
        self.spacingV = 100
        self.startV = 100
        self.endV = 101
        #Default colors for vertical Line
        self.colorV = 'red'
        self.colorV1 = ImageColor.getrgb("#0000ff")

        self.y1 = 0
        self.y2 = self.height

        #if Wide Ruled, spaced farther
        if ((option == "wide") or (option == "colg")):
            if (option == "wide"):
                self.spacing = 40
            else:
                self.spacing = 30

            self.pink = '#f08080'
            self.x2 = 750
            self.x1 = 750

            self.cv.create_line(self.x1, self.y1, self.x2, self.y2, fill=self.pink)
            if (self.publishN.get()):

                self.drawing.line((self.x1, self.y1, self.x2, self.y2), (240, 128, 128))

        elif (option == "page"):
            return

        elif (option == "grid"):
            self.start = 0
            self.startV = 0
            self.spacingV = self.spacing = 30
            self.endV = self.width
            self.colorV = "#0000ff"



        #Start drawing out the horizontal lines
        self.x1 = 0
        self.x2 = self.width
        for k in range(self.start, self.end, self.spacing):
            self.y1 = k
            self.y2 = k
            self.cv.create_line(self.x1, self.y1, self.x2, self.y2, fill='blue')
            if (self.publishN.get()):

                self.drawing.line((self.x1, self.y1, self.x2, self.y2), (0, 0, 255))

        #Start drawing out the vertical lines
        self.y1 = 0
        self.y2 = self.height

        for k in range(self.startV, self.endV, self.spacingV):
            self.x1 = k
            self.x2 = k
            self.cv.create_line(self.x1, self.y1, self.x2, self.y2, fill=self.colorV)
            if (self.publishN.get()):

                self.drawing.line((self.x1, self.y1, self.x2, self.y2), self.colorV)
#If drawing the yellow notepad, draw a second vertical red line
        if (option == "npad"):
            self.spacing = 40
            self.x1 = 110
            self.x2 = 110
            self.cv.create_line(self.x1, self.y1, self.x2, self.y2, fill=self.colorV)
            if (self.publishN.get()):

                self.drawing.line((self.x1, self.y1, self.x2, self.y2), self.colorV)

        else:
        #Draw the 3 holes on the notebook
            self.rad = 12
            self.x = 50

            for self.y in range(120, self.height, 340):
                self.cv.create_oval(self.x-self.rad, self.y-self.rad, self.x + self.rad,
                                    self.y + self.rad, width=1, fill="#545454")
                if (self.publishN.get()):

                    self.drawing.ellipse((self.x-self.rad, self.y-self.rad, self.x + self.rad,
                                     self.y + self.rad), "#545454")


    #Delete currently displayed file... if it exists.
    def delNotes(self):
        result = tkMessageBox.askyesno("Delete Notes", "Are you sure you want to delete your notes?")
        if (result):

            if (os.path.exists(self.currentFileName)):

                os.remove(self.currentFileName)
                try:

                    if self.currentFileName in self.list: self.list.remove(self.currentFileName)
                    self.files.remove(self.currentFileName)
                except (ValueError):
                    pass
                self.saved = 1
                total = len(self.list)


                if (total>= 1):

                    self.count = self.count -1
                    self.nextImage()

                if (total==0):
                    self.drawNewPage()
                    self.nextBtn.configure(state=DISABLED)
                    self.prevBtn.configure(state=DISABLED)


        #Open the image and display on the screen
    def openImage(self, filepath, temp):
        if (temp == 0):
            self.menubar.entryconfig(11, label=filepath)
        self.currentFileName = filepath
        try:
            self.photo = PhotoImage(file=filepath)
            del self.background
            #KEEP the RGB...else you can't save it in different colors.
            self.background = Image.open(filepath).convert("RGB")
            self.drawing = ImageDraw.Draw(self.background)
            self.cv.delete(ALL)
            self.cv.create_image(0, 0, image=self.photo, anchor=NW)

        except(TclError):
            print "Error in loading image."
            self.cv.delete(ALL)


        self.cv.update()
        self.cv.pack()

        if (filepath[-10:-9]=="_" and filepath[-9:-8]=="p"):
            self.publishN.set(1)
            self.pub = "p"
            self.menubar.entryconfig(10, state=DISABLED)
            self.papermenu.entryconfig(2, state=DISABLED)
            self.papermenu.entryconfig(3, state=DISABLED)
            self.papermenu.entryconfig(4, state=DISABLED)
            self.papermenu.entryconfig(5, state=DISABLED)
            self.papermenu.entryconfig(6, state=DISABLED)
        else:
            self.publishN.set(0)
            self.pub = "u"
            self.menubar.entryconfig(10, state=NORMAL)
            self.papermenu.entryconfig(2, state=NORMAL)
            self.papermenu.entryconfig(3, state=NORMAL)
            self.papermenu.entryconfig(4, state=NORMAL)
            self.papermenu.entryconfig(5, state=NORMAL)
            self.papermenu.entryconfig(6, state=NORMAL)


        option = self.currentFileName[-8:-4]

        self.option = option

        if(option == "colg"):
            self.drawLines("colg")
        elif(option == "wide"):
            self.drawLines("wide")
        elif(option == "grid"):
            self.drawLines("grid")
        elif(option == "npad"):
            self.drawLines("npad")

        self.saved = 1


    #Display a list of notes singly
    def displaySetNotes(self, list, mode):
        self.list = list
        if (len(self.list) > 0):
            self.nextBtn.configure(state=NORMAL)
            self.prevBtn.configure(state=NORMAL)
            self.openImage(self.list[0], 0)

        self.fromNotesMan = mode

    #Display the next notes onto the screen
    def nextImage(self):

        self.checkIfSaved(1);
        total = len(self.list)
        if (total>0):

            if (self.count == total-1):
                self.count = 0
            else:
                self.count += 1
            self.openImage(self.list[self.count], 0)

    #Display the previous notes onto the screen
    def prevImage(self):
        self.checkIfSaved(1);
        total = len(self.list)
        if (total > 0):
            if (self.count > 0):
                self.count -= 1
            else:
                self.count = total-1
            self.openImage(self.list[self.count],0)

    #Allow user to select multiple files to open
    def openFile(self):

        if (self.saved==0):
            result = tkMessageBox.askyesnocancel("Unsaved Notes", "Would you like to save your notes?")
            if (result):
                self.saveFile()

        if (os.path.exists(self.untitledFile)):
            os.remove(self.untitledFile)

        self.files = list(tkFileDialog.askopenfilename(title="Open My Notes", ** self.optionOpen))

        total = len(self.files)
        if (total > 1):
            self.nextBtn.configure(state=NORMAL)
            self.prevBtn.configure(state=NORMAL)
            self.displaySetNotes(self.files,0)
            return

        elif (total == 1):
            self.openImage(self.files[0], 0)
        self.nextBtn.configure(state=DISABLED)
        self.prevBtn.configure(state=DISABLED)

    def publishNotes(self):
        if (self.publishN.get()):

            result = tkMessageBox.askyesno("Publish My Notes, Please!", "Are you sure you want to publish your notes?  All changes are final.")

            if (result):
                self.pub = "p"
                self.drawLines(self.option)

                self.menubar.entryconfig(10, state=DISABLED)
                self.papermenu.entryconfig(2, state=DISABLED)
                self.papermenu.entryconfig(3, state=DISABLED)
                self.papermenu.entryconfig(4, state=DISABLED)
                self.papermenu.entryconfig(5, state=DISABLED)
                self.papermenu.entryconfig(6, state=DISABLED)
                self.saveFile()

            else:
                self.publishN.set(0)
                self.pub = "u"
                self.menubar.entryconfig(10, state=DISABLED)
                self.papermenu.entryconfig(2, state=NORMAL)
                self.papermenu.entryconfig(3, state=NORMAL)
                self.papermenu.entryconfig(4, state=NORMAL)
                self.papermenu.entryconfig(5, state=NORMAL)
                self.papermenu.entryconfig(6, state=NORMAL)




    #Display a save window if user had opened a newly loaded notes/new notes
    #Else, it will save directly to the already saved filename
    def saveFile(self):

        if (self.option == self.currentFileName[-8:-4]):

            self.saved = 1


        if (self.saved == 0):
            os.system('onboard&')

            name = tkFileDialog.asksaveasfilename(parent=self.root, title="Save My Notes", filetypes=[("gif", '.gif'), ("ppm", '.ppm')])#, initialfile=timestamp)
            os.system('killall onboard')
            self.currentFileName = name
            if len(name) == 0:
                return
            self.format = self.currentFileName[-4:]

            if (os.path.exists(self.currentFileName)):
                    try:
                        if self.currentFileName in self.list: self.list.remove(self.currentFileName)
                        os.remove(self.currentFileName)

                    except(ValueError):
                        print "couln't remove item in list"
                        pass


                    option = self.currentFileName[-8:-4]

                    if (self.currentFileName[-10:-9]=="_"):
                        self.currentFileName = self.currentFileName[0:-10] + self.currentFileName[-4:]


                    self.currentFileName = self.currentFileName[0: -4] + "_" + self.pub + self.option + self.format
                    self.files.append(self.currentFileName)
            else:

                self.currentFileName = self.currentFileName[0: -4] + "_" + self.pub + self.option + self.format
        else:
            try:
                if self.currentFileName in self.list: self.list.remove(self.currentFileName)

            except(ValueError):

                pass
            os.remove(self.currentFileName)

            self.format = self.currentFileName[-4:]
            if (self.currentFileName[-10:-9]=="_"):
                self.currentFileName = self.currentFileName[0:-10] + self.currentFileName[-4:]

            self.currentFileName = self.currentFileName[0: -4] + "_" + self.pub + self.option + self.format
            self.list.append(self.currentFileName)
            self.list.sort()
        #Now Saving the image onto a file
        try:
            if(self.option != "page"):
                self.drawLines(self.option)

            self.background.save(self.currentFileName)
            self.saved = 1
            self.menubar.entryconfig(11, label=self.currentFileName)

        except (ValueError, AttributeError):
            print" error in saving"


    #Check if file is saved before quitting
    def checkIfSaved(self, mode):
        if (mode == 0):
            if (self.saved == 0):
                result = tkMessageBox.askyesnocancel("Unsaved Notes", "Would you like to save your notes?")
                if (result):
                    self.saveFile()
                elif (result == 0):
                    if (self.fromNotesMan==1):
                        self.obj.notesList.focus("toplevel")
                        self.obj.update_tree()
                    self.root.destroy()
            else:

                if (self.fromNotesMan==1):
                        self.obj.notesList.focus("toplevel")
                        self.obj.update_tree()
                self.root.destroy()
        else:

            if (self.saved == 0):
                result = tkMessageBox.askyesno("Unsaved Notes", "Would you like to save your notes?")
                if (result):
                    self.saveFile()
            return
    #Have it check if the notes have been written before quitting
    def quitNotes(self):
        self.checkIfSaved(0)
    #Change color of user's brush to color of background to allow "erasing"

    def getEraser(self):
       if (self.erase == 1):
           self.option = self.lastoption

           self.drawLines(self.option)
           self.erase = 0
           self.cv.config(cursor="pencil")
           self.menubar.entryconfig(6, background='light gray')
           self.color = self.lastColor
           self.drawLines(self.option)
           self.BrSize = self.penSize
       else:
           self.lastoption=self.option
           self.drawBlank()
           self.erase = 1
           self.lastColor = self.color
           self.menubar.entryconfig(6, background='dark gray')
           self.cv.config(cursor="box_spiral")
           self.color = "#ffffff"
           self.BrSize = self.eraSize

    #Obtains color for user and set it to color of brush
    def askPenColor(self):
        thecolor = askcolor(parent=self.root, initialcolor='#000000')
        if (thecolor[0] == None):
            thecolor = ((0, 0, 0), '#000000')

        if (self.erase == 1):
            self.menubar.entryconfig(6, background='light gray')
            self.erase = 0

        try:
            self.color = thecolor[1]
            self.cv.config(cursor="pencil")
        except(AttributeError):
            self.color = "#000000"

    #Create all the widgets in the notes class
    def createWidgets(self):
        #Create a new canvas
        self.width = 900
        self.height = 1100

        self.cv = Canvas(self.root, width=self.width, height=self.height, bg="white",
                         scrollregion=(0, 0, 730, 930))

        self.background = Image.new("RGB", (self.width, self.height), self.white)
        self.drawing = ImageDraw.Draw(self.background)

        self.cv.config(highlightthickness=0)
        self.cv.config(cursor="pencil")

        self.right  = PhotoImage(file='icons/right-icon.gif')
        self.nextBtn = Button(self.root, image=self.right, height=30, bg="dark gray", state=DISABLED, command=self.nextImage)
        self.nextBtn.image = self.right
        self.nextBtn.pack(side=RIGHT, expand=YES, fill=BOTH)


        sbar = Scrollbar(self.root)
        sbar.config(command=self.cv.yview)
        self.cv.config(yscrollcommand=sbar.set)
        sbar.pack(side=RIGHT, fill=Y)

        self.left = PhotoImage(file='icons/left-icon.gif')
        self.prevBtn = Button(self.root, image = self.left, height=30, bg="dark gray", state=DISABLED, command=self.prevImage)
        self.prevBtn.image = self.left
        self.prevBtn.pack(side=LEFT, expand=YES, fill=BOTH)

        self.cv.pack(side=LEFT, expand=YES, fill=BOTH)

        #Bind the canvas to mouse action
        self.cv.bind("<Button-1>", self.recordLastXY)
        self.cv.bind("<B1-Motion>", self.connectLine)


#Record the last x and y coordinates
    def recordLastXY(self, event):
        self.lastx = self.cv.canvasx(event.x)
        self.lasty = self.cv.canvasy(event.y)

    #Connect the lines as it is drawn
    def connectLine(self, event):
        self.saved=0
        x = self.cv.canvasx(event.x)
        y = self.cv.canvasy(event.y)
        try:

            self.cv.create_line((self.lastx, self.lasty, x, y), fill=self.color,
                                width=self.BrSize)

            self.drawing.line((self.lastx, self.lasty, x, y), fill=ImageColor.getrgb(self.color),
                              width=self.BrSize)

        except(AttributeError):
            print "error in drawing lines"

            self.color = "#000000"
            self.cv.create_line((self.lastx, self.lasty, x, y), fill=self.color,
                                width=self.brushSize.get())

            self.drawing.line((self.lastx, self.lasty, x, y), fill=ImageColor.getrgb(self.color),
                              width=self.brushSize.get())

        self.lastx = x
        self.lasty = y

    #Create the menu with images

    def createMenu(self):
        self.folderPic = PhotoImage(file="icons/folder.gif")
        self.homePic = PhotoImage(file="icons/Login-out-icon.gif")
        self.brushColorPic = PhotoImage(file="icons/brushcolor.gif")
        self.erasorPic = PhotoImage(file="icons/eraser.gif")
        self.paper = PhotoImage(file="icons/papers.gif")
        self.savePic = PhotoImage(file="icons/filesave.gif")
        self.brushSizePic = PhotoImage(file="icons/brushsize.gif")
        self.helpPic = PhotoImage(file="icons/help_and_support.gif")

        self.papersPic = PhotoImage(file="icons/papers.gif")
        self.trashPic = PhotoImage(file="icons/File-delete-icon.gif")
        self.menubar = Menu(self.root, background="light gray")

        # create a pulldown menu, and add it to the menu bar
        self.menubar.add_command(image=self.homePic, command=self.quitNotes)
        self.menubar.add_command(image=self.folderPic, command=self.openFile)
        self.menubar.add_command(image=self.savePic, command=self.saveFile)

        self.menubar.add_command(image=self.brushSizePic, command=self.selectSize)
        self.menubar.add_command(image=self.brushColorPic, command=self.askPenColor)
        self.menubar.add_command(image=self.erasorPic, command=self.getEraser)

        self.papermenu = Menu(self.menubar, tearoff=1)
        self.papermenu.add_command(label="New", command=self.drawNPage)
        self.papermenu.add_command(label="Plain", command=self.drawBlank)
        self.papermenu.add_command(label="College-Ruled", command=self.drawCollege)
        self.papermenu.add_command(label="Wide-Ruled", command=self.drawWide)
        self.papermenu.add_command(label="NotePad", command=self.drawPad)
        self.papermenu.add_command(label="Grid", command=self.drawGrid)

        self.menubar.add_cascade(image=self.papersPic, menu=self.papermenu)

        self.menubar.add_command(image=self.helpPic, command=self.getHelp)
        self.menubar.add_command(image=self.trashPic, command=self.delNotes)

        self.menubar.add_checkbutton(label="Publish My Notes"+"                                             "+"              ", onvalue=True, offvalue=False, variable=self.publishN, command = self.publishNotes)

        self.menubar.add_command(label=self.path + "/" + "Untitled.gif")
        # display the menu
        self.root.config(menu=self.menubar)
    